use crate::core::coin::Coin;
use crate::utils::{encrypt, time};

/// 区块
#[derive(Debug)]
pub struct Block {
    index: usize,
    timestamp: i64,
    beat_per_minute: u64,
    prev_hash: String,
    coin: Coin,
    hash: String,
}

impl Block {
    /// 创建上帝节点
    pub fn god() -> Self {
        let mut g = Block {
            index: 0,
            timestamp: time::now(),
            beat_per_minute: 0,
            prev_hash: String::new(),
            coin: Coin::new("god", "50.00"),
            hash: String::new(),
        };
        g.refresh_self("");
        g
    }

    /// 生成一个新的区块
    pub fn new(prev_block: &Block, beat_per_minute: u64, coin: Coin) -> Self {
        let prev_hash = Self::calculate_hash(prev_block);
        let mut b = Block {
            index: prev_block.index + 1,
            timestamp: time::now(),
            beat_per_minute,
            prev_hash: String::new(),
            coin,
            hash: String::new(),
        };
        b.refresh_self(&prev_hash);
        b
    }

    /// 计算一个区块的hash值
    pub fn calculate_hash(block: &Self) -> String {
        let identification = format!("{}{}{}{}",
                                     block.index,
                                     block.timestamp,
                                     block.beat_per_minute,
                                     block.prev_hash);
        encrypt::encrypt_un_back(identification.as_ref())
    }
}

impl Block {
    /// 刷新自身的 prev_hash 和 hash值
    pub fn refresh_self(&mut self, prev_hash: &str) {
        self.prev_hash = prev_hash.to_string();
        let hash = Self::calculate_hash(self);
        self.hash = hash;
    }

    /// 检查自身的合法性
    pub fn check_legality(&self, prev: &Self) -> bool {
        prev.hash.eq(self.prev_hash.as_str())
            && prev.index == self.index + 1
            && Self::calculate_hash(self).eq(self.hash.as_str())
    }
}

